/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */

package org.openmrs.module.datalogging.advice;

import org.apache.commons.lang.ClassUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Obs;
import org.openmrs.api.context.Context;
import org.openmrs.module.datalogging.configuration.Event;
import org.openmrs.module.datalogging.configuration.Variable;
import org.openmrs.module.datalogging.enums.EventType;
import org.openmrs.module.datalogging.handler.event.EventHandler;
import org.openmrs.module.datalogging.handler.event.EventHandlerFactory;
import org.openmrs.module.datalogging.handler.variable.VariableHandler;
import org.openmrs.module.datalogging.handler.variable.VariableHandlerFactory;
import org.openmrs.module.datalogging.model.LogEntry;
import org.openmrs.module.datalogging.model.LogEvent;
import org.openmrs.module.datalogging.service.DataLoggingService;
import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;

/**
 *
 */
public class ObsCreatedAdvice implements AfterReturningAdvice {

	private static final Log log = LogFactory.getLog(ObsCreatedAdvice.class);

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		if (method.getName().equals("saveObs")) {

			if (log.isDebugEnabled())
				log.debug("Processing event observation ...");

			try {
				Obs obs = (Obs) returnValue;
				if (obs != null) {
					DataLoggingService service = Context.getService(DataLoggingService.class);
					List<Event> events = service.getEventsByEvent(EventType.EVENT_ENCOUNTER_SAVED);
					for (Event event : events) {
						EventHandler eventHandler = EventHandlerFactory.getHandler(event.getEventType());
						if (eventHandler.allow(event, obs)) {
							LogEvent logEvent = new LogEvent();
							logEvent.setPerson(obs.getPerson());
							logEvent.setEvent(event);
							for (Variable variable : event.getVariables()) {
								VariableHandler handler = VariableHandlerFactory.getHandler(variable.getVariableType());
								LogEntry entry = new LogEntry();
								entry.setLogEvent(logEvent);
								entry.setVariable(variable);
								entry.setPerson(obs.getPerson());
								Object object = handler.handle(obs.getPerson(), variable, obs);
								if (object != null) {
									if (ClassUtils.isAssignable(object.getClass(), Date.class))
										entry.setValueDatetime((Date) object);
									else if (ClassUtils.isAssignable(object.getClass(), Double.class))
										entry.setValueNumeric((Double) object);
									else
										entry.setValueText(String.valueOf(object));
								}
								logEvent.addEntry(entry);
							}
							service.saveLogEvent(logEvent);
						}
					}
				}
			} catch (Exception e) {
				log.error("Bailing out from executing advice due to exception.", e);
			}
		}
	}

}
